<template>
	<view class="option" :style="{'width': width,'height': height}" ref="dropdown">
		<view class="option-select-title" @click="fnShowOptionList()">
			<input class="inp-select" placeholder="请选择" :value="value" disabled />
			<!-- 箭头图标 -->
			<view class="trans" :class="showOptionList?'trans-from':''">
				<um-icon name="down"></um-icon>
			</view>
		</view>
		<!-- 下拉列表 -->
		<view class="option-list" :style="[{height: ListHeightVal}, addStyle(listStyle)]">
			<view class="option-list-padding">
				<block v-for="(item, index) in optionList" :key="index">
					<view class="option-item" :style="[addStyle(selectItemIdx == index ? selectedItemStyle: itemStyle)]"
						@click.stop="fnChangeOption(item, index)">
						{{rangeKey? item[rangeKey]: item}}
					</view>
				</block>
			</view>
		</view>
	</view>
</template>

<script>
	/**
	 * @param optionList {Array} 下拉列表数据
	 * @example <um-dropdown  :optionList="optionList"></um-dropdown>/>
	 */
	export default {
		props: {
			// 菜单非选中时的样式
			itemStyle: {
				type: [String, Object],
				default: () => ({
					color: '#333',
					fontSize: '28rpx'
				})
			},
			// 菜单选择中时的样式
			selectedItemStyle: {
				type: [String, Object],
				default: () => ({
					color: '#2973F8',
					fontSize: '28rpx',
					background: '#F5F7FA'
				})
			},
			// 自定义列表样式
			listStyle: {
				type: [String, Object],
				default: '',
			},
			// 列表数据
			optionList: {
				type: Array,
				default: function() {
					return []
				}
			},
			// 选择框的宽度
			width: {
				type: String,
				default: '100%'
			},
			// 选择框的高度
			height: {
				type: String,
				default: '100%'
			},
			// 如果数组包含对象时，需要显示的key值
			rangeKey: {
				type: String,
				default: ''
			},
			// 默认选中的下标
			defaultIndex: {
				type: [String, Number],
				default: ''
			},
			// 列表高度，若不设置会展示所有列表选项
			listHeight: {
				type: String,
				default: ''
			},

		},
		data() {
			return {
				selectItem: '', // 选中的值
				selectItemIdx: null, // 选中的下标
				showOptionList: false, // 显示下拉
			}
		},
		computed: {
			value() {
				if (!this.selectItem && this.defaultIndex !== '' && this.optionList.length) {
					this.selectItemIdx = this.defaultIndex
					let _val = this.rangeKey ? this.optionList[this.defaultIndex][this.rangeKey] : this.optionList[this
						.defaultIndex]
					this.$emit('change', this.optionList[this.defaultIndex])
					return _val
				} else if (this.selectItem) {
					return this.rangeKey ? this.selectItem[this.rangeKey] : this.selectItem
				} else {
					return ''
				}
			},
			ListHeightVal() {
				if (this.showOptionList) {
					if (this.listHeight) {
						return this.listHeight
					} else {
						// 70是单行高度，24是列表上下内边距
						return (this.optionList.length * 70 + 24) + 'rpx'
					}
				} else {
					return '0'
				}

			}
		},
		// #ifdef H5
		mounted() {
			document.addEventListener('click', this.handleDocumentClick);
		},
		beforeDestroy() {
			document.removeEventListener('click', this.handleDocumentClick);
		},
		// #endif
		methods: {
			// 点击组件外部区域时自动收起菜单
			handleDocumentClick(e) {
				const dropdown = this.$refs.dropdown.$el;
				if (dropdown && !dropdown.contains(e.target)) {
					this.showOptionList = false;
				}
			},
			// 控制列表显示与隐藏
			fnShowOptionList() {
				this.$emit('click')
				this.$emit('selectState', this.showOptionList)
				if (this.optionList.length) {
					this.showOptionList = !this.showOptionList
				} else {
					// 如果列表为空，发送一个事件
					this.$emit('openNull')
					console.log('mu-dropdown列表数据唯空无法展开')
				}

			},
			// 点击列表时触发
			fnChangeOption(item, index) {
				this.selectItem = item
				this.selectItemIdx = index
				this.showOptionList = false
				this.$emit('change', item, this.showOptionList)
			},
			/**
			 * @description 样式转换
			 * 对象转字符串，或者字符串转对象
			 * @param {object | string} customStyle 需要转换的目标
			 * @param {String} target 转换的目的，object-转为对象，string-转为字符串
			 * @returns {object|string}
			 */
			addStyle(customStyle, target = 'object') {
				// 字符串转字符串，对象转对象情形，直接返回
				if (this.empty(customStyle) || typeof(customStyle) === 'object' && target === 'object' || target ===
					'string' &&
					typeof(customStyle) === 'string') {
					return customStyle
				}
				// 字符串转对象
				if (target === 'object') {
					// 去除字符串样式中的两端空格(中间的空格不能去掉，比如padding: 20px 0如果去掉了就错了)，空格是无用的
					customStyle = this.trim(customStyle)
					// 根据";"将字符串转为数组形式
					const styleArray = customStyle.split(';')
					const style = {}
					// 历遍数组，拼接成对象
					for (let i = 0; i < styleArray.length; i++) {
						// 'font-size:20px;color:red;'，如此最后字符串有";"的话，会导致styleArray最后一个元素为空字符串，这里需要过滤
						if (styleArray[i]) {
							const item = styleArray[i].split(':')
							style[this.trim(item[0])] = this.trim(item[1])
						}
					}
					return style
				}
				// 这里为对象转字符串形式
				let string = ''
				for (const i in customStyle) {
					// 驼峰转为中划线的形式，否则css内联样式，无法识别驼峰样式属性名
					const key = i.replace(/([A-Z])/g, '-$1').toLowerCase()
					string += `${key}:${customStyle[i]};`
				}
				// 去除两端空格
				return this.trim(string)
			},

			/**
			 * @description 去除空格
			 * @param String str 需要去除空格的字符串
			 * @param String pos both(左右)|left|right|all 默认both
			 */
			trim(str, pos = 'both') {
				str = String(str)
				if (pos == 'both') {
					return str.replace(/^\s+|\s+$/g, '')
				}
				if (pos == 'left') {
					return str.replace(/^\s*/, '')
				}
				if (pos == 'right') {
					return str.replace(/(\s*$)/g, '')
				}
				if (pos == 'all') {
					return str.replace(/\s+/g, '')
				}
				return str
			},
			/**
			 * 判断是否为空
			 */
			empty(value) {
				switch (typeof value) {
					case 'undefined':
						return true
					case 'string':
						if (value.replace(/(^[ \t\n\r]*)|([ \t\n\r]*$)/g, '').length == 0) return true
						break
					case 'boolean':
						if (!value) return true
						break
					case 'number':
						if (value === 0 || isNaN(value)) return true
						break
					case 'object':
						if (value === null || value.length === 0) return true
						for (const i in value) {
							return false
						}
						return true
				}
				return false
			}

		}
	}
</script>

<style lang="scss">
	// 去掉列表滚动条
	::-webkit-scrollbar {
		display: none;
	}

	.mask {
		width: 100vw;
		height: 100vh;
		position: fixed;
		position: relative;
		background: #A3A3A3;
		opacity: .5;
		z-index: 9;
	}

	.option {
		width: 100%;
		height: 100%;
		position: relative;
		border: 1rpx solid #A3A3A3;
		border-radius: 10rpx;

		.option-select-title {
			height: 100%;
			padding: 0 20rpx;
			display: flex;
			justify-content: space-between;
			align-items: center;

			.inp-select {
				width: 100%;
				height: 100%;
			}

			.trans {
				transition: transform 0.2s;
			}

			.trans-from {
				transform: rotate(-180deg);
			}

		}

		.option-list {
			box-sizing: content-box;
			width: calc(100% - 20rpx);
			// height: 0;
			border-radius: 25rpx;
			background: #FFF;
			overflow: scroll;
			position: absolute;
			top: calc(100% + 20rpx);
			left: 10rpx;
			right: 10rpx;
			z-index: 10;
			box-shadow: 0 0 15rpx #A3A3A3;
			transition: height .2s;

			.option-list-padding {
				padding: 12rpx 0;
			}

			.option-item {
				height: 60rpx;
				text-align: center;
				line-height: 70rpx;
			}

		}


	}
</style>